/***************************************************************************
 *                                                                         *
 *   This file is part of the Fotowall project,                            *
 *       http://code.google.com/p/fotowall                                 *
 *                                                                         *
 *   Copyright (C) 2007-2009 by Enrico Ros <enrico.ros@gmail.com>          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 * ----------------------------------------------------------------------- *
 *																		   *
 *	Modifications for FotoKinect, Spring 2011 by Gianna Badiali,		   *
 *                                                   Gabriel Fernandez,	   *
 *                                                   Kelsey Tripp, and     *
 *                                                   Sam Swarr             *
 *																		   *
 ***************************************************************************/

#include "MainWindow.h"

#include <QPropertyAnimation>
#include <QStateMachine>
#include <QState>
#include <QSignalTransition>
#include <qstringlist.h>
#include "ColorState.h"
#include <QParallelAnimationGroup>
#include <QString>
#include "devices\devicemanager.h"
#include "Desk.h"
#include "ExactSizeDialog.h"
#include "ExportWizard.h"
#include "MetaXmlReader.h"
#include "ModeInfo.h"
#include "RenderOpts.h"
#include "VersionCheckDialog.h"
#include "WarningBox.h"
#include "XmlRead.h"
#include "XmlSave.h"
#include <QAction>
#include <QApplication>
#include <QDir>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QFileDialog>
#include <QFile>
#include <QImageReader>
#include <QInputDialog>
#include <QMenu>
#include <QMessageBox>
#include <QPushButton>
#include <QSettings>
#include <QTimer>
#include <QVBoxLayout>
#include <iostream>
#include <float.h>
#include <qpixmap.h>
#include <qthread.h>
#include <map>
#include <qdir.h>

//The QCommonStyle class encapsulates the common Look and Feel of a GUI.

//From Fotowall, takes care of the drawing of the "rubber band", or selection rectangle.  
//We use it for our cropping tool.
#include <QCommonStyle>
class RubberBandStyle : public QCommonStyle {
public:
    void drawControl(ControlElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget = 0) const
    {
        if (element == CE_RubberBand) {
            painter->save();
            QColor color = option->palette.color(QPalette::Highlight);
            painter->setPen(color);
            color.setAlpha(80); painter->setBrush(color);
            painter->drawRect(option->rect.adjusted(0,0,-1,-1));
            painter->restore();
            return;
        }
        return QCommonStyle::drawControl(element, option, painter, widget);
    }
    int styleHint(StyleHint hint, const QStyleOption * option, const QWidget * widget, QStyleHintReturn * returnData) const
    {
        if (hint == SH_RubberBand_Mask)
            return false;
        return QCommonStyle::styleHint(hint, option, widget, returnData);
    }
};

//This is a subclass of a GraphicsView that will be instantiated as the Desk.
#include <QGraphicsView>
class FWGraphicsView : public QGraphicsView {
public:
    FWGraphicsView(QWidget * parent)
        : QGraphicsView(parent)
        , m_desk(0)
    {
        // customize widget
        setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
        setInteractive(true);
        setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing /*| QPainter::SmoothPixmapTransform */);
        setDragMode(QGraphicsView::RubberBandDrag);
        setAcceptDrops(true);
        setFrameStyle(QFrame::NoFrame);

        // don't autofill the view with the Base brush
        QPalette pal;
        pal.setBrush(QPalette::Base, Qt::NoBrush);
        setPalette(pal);

        // use own style for drawing the RubberBand (opened on the viewport)
        viewport()->setStyle(new RubberBandStyle);
    }

    void setDesk(Desk * desk)
    {
        setScene(desk);
        m_desk = desk;
    }

protected:
    void resizeEvent(QResizeEvent * event)
    {
        if (m_desk)
            m_desk->resize(contentsRect().size());
        QGraphicsView::resizeEvent(event);
    }


private:
    Desk * m_desk;
};

// added here because it needs the FWGraphicsView declaration
#include "ui_MainWindow.h"

MainWindow::MainWindow(QWidget * parent)
    : QWidget(parent)
    , ui(new Ui::MainWindow())
    , m_desk(0)
	, m_machine(0)
    , m_firstCursor(0)
    , m_showCursorOneFoundInstr(0)
    , m_showCursorTwoFoundInstr(0)
    , m_menuOpen(false)
    , m_importState(0)
    , m_cropState(0)
	, m_cropP1()
	, m_cropP2()
	, m_helpState(0)
	, m_menuState(0)
	, m_colorState(0)
	, m_loadState(0)
{
	//NO MOUSE
	setCursor(QCursor(Qt::BlankCursor));
	//timer for tool tips
	m_hideLostInstr1Timer = new QTimer(this);
	m_hideLostInstr2Timer = new QTimer(this);
	m_hideLostInstrBeginTimer = new QTimer(this);
	m_cursorDetectedTimer = new QTimer(this);
	m_cursorDetected2Timer = new QTimer(this);
	m_savedTimer = new QTimer(this);
	m_exportedTimer = new QTimer(this);
	m_erasedTimer = new QTimer(this);
	m_cursor1GreenTimer = new QTimer(this);
	m_cursor2GreenTimer = new QTimer(this);
	m_noPicturesToCropTimer = new QTimer(this);
	m_connectedNotificationTimer = new QTimer(this);

	connect(m_hideLostInstr1Timer, SIGNAL(timeout()), this, SLOT(slotHideLostCursorInstr()));
	connect(m_hideLostInstr2Timer, SIGNAL(timeout()), this, SLOT(slotHideLostCursorInstr2()));
	connect(m_hideLostInstrBeginTimer, SIGNAL(timeout()), this, SLOT(slotHideLostCursorInstrBegin()));
	connect(m_cursorDetectedTimer, SIGNAL(timeout()), this, SLOT(slotHideCursorDetected()));
	connect(m_cursorDetected2Timer, SIGNAL(timeout()), this, SLOT(slotHideCursorDetected2()));
	connect(m_savedTimer, SIGNAL(timeout()), this, SLOT(slotHideSaveNotification()));
	connect(m_exportedTimer, SIGNAL(timeout()), this, SLOT(slotHideExportNotification()));
	connect(m_erasedTimer, SIGNAL(timeout()), this, SLOT(slotHideEraseNotification()));
	connect(m_cursor1GreenTimer, SIGNAL(timeout()), this, SLOT(slotRevertCursor1()));
	connect(m_cursor2GreenTimer, SIGNAL(timeout()), this, SLOT(slotRevertCursor2()));
	connect(m_noPicturesToCropTimer, SIGNAL(timeout()), this, SLOT(slotHideNoPicturesToCrop()));
	connect(m_connectedNotificationTimer, SIGNAL(timeout()), this, SLOT(slotHideConnectedNotification()));

    // setup widget
    QRect geom = QApplication::desktop()->availableGeometry();
    resize(2 * geom.width() / 3, 2 * geom.height() / 3);
#if QT_VERSION >= 0x040500
    setWindowTitle(qApp->applicationName() + " " + qApp->applicationVersion());
#else
    setWindowTitle(qApp->applicationName() + " " + qApp->applicationVersion() + "   -Limited Edition (Qt 4.4)-");
#endif
    setWindowIcon(QIcon(":/data/fotowall.png"));

    // create our custom desk
    m_desk = new Desk(this);

    // init booleans
    m_firstCursor=true;
    m_showCursorOneFoundInstr=false;
    m_showCursorTwoFoundInstr=false;
	m_firstTimeInEmptyState=true;

    // init ui
    ui->setupUi(this);
    ui->canvas->move(0,0);
    ui->canvas->setDesk(m_desk);
    ui->canvas->setFocus();

    m_machine = new QStateMachine;

	//init states.
    m_emptyState = new QState(m_machine);
    hideAllExtraWidgets(m_emptyState);
    m_machine->setInitialState(m_emptyState);


	//make mainWindow non-resizable.
    setFixedSize(geom.width(), geom.height());
    ui->canvas->resize(geom.width(), geom.height());

	//resize all necessary widgets.   
    ui->helpButton->resize(140,120);
    ui->trashButton->resize(130,130);
    ui->menuButton->resize(200,100);
    ui->quitButton->resize(140,120);

	//move all necessary widgets to proper places in the UI.
	ui->waitingForDeviceInput->move(width()/2-(ui->waveInstruction->width()/2)+110, height()/2-(ui->waveInstruction->height()/2)+200);
	ui->title->move(width()/2 - ui->title->width()/2, height()/2 - ui->title->height()/2);
    ui->quitButton->move(width()-ui->helpButton->width(), 10);
    ui->helpButton->move(0, 10);
    ui->trashButton->move(width()-ui->trashButton->width()-20,height()-ui->trashButton->height()-40);
    ui->menuButton->move(10,height()-ui->helpButton->height()-10);

	//hide all unnecessary widgets.
	ui->helpWidget->move(width(),-height());
	ui->cursorDetected->move(0,height());
	ui->cursorDetected2->move(0,height());
    ui->cursorLostInstructionBegin->move(0,height());
    ui->cursorLostInstruction->move(0, height());
    ui->cursorLostInstruction2->move(0, height());
    ui->importInstruction->move(0, height());
    ui->pushInstruction->move(0,height());
	ui->pushDiagram->move(0,height());
	ui->importMenu->move(0, this->height());
	ui->importMenuThumb1->move(0, this->height());
	ui->importMenuThumb2->move(0, this->height());
	ui->importMenuThumb3->move(0, this->height());
	ui->importBackground->move(0, this->height());
	ui->loadInstructions->move(0, height());
	ui->leftArrow->move(0, height());
	ui->rightArrow->move(0, height());
	ui->importMenuButton->move(0, height());
	ui->colorInstructions->move(0, height());
	ui->closeButton->move(0, height());
	ui->undoButton->move(0, height());
	ui->noProjectNotification->move(0, height());
	ui->loadMenu->move(0, this->height());
	ui->loadMenuThumb1->move(0, this->height());
	ui->loadMenuThumb2->move(0, this->height());
	ui->loadMenuThumb3->move(0, this->height());
	ui->loadMenuTime->move(0, this->height());
	ui->loadMenuThumb1Time->move(0, this->height());
	ui->loadMenuThumb2Time->move(0, this->height());
	ui->loadMenuThumb3Time->move(0, this->height());
	ui->pushDiagram->move(0,this->height());
	ui->eraseNotification->move(0, this->height());
	ui->cropNotification->move(0, this->height());
	ui->exportNotification->move(0, this->height());
	ui->eraseNotification->move(0, this->height());
	ui->saveNotification->move(0, this->height()); 
	ui->exportDirectory->move(0, this->height());
	ui->projectsDirectory->move(0, this->height());
	ui->noPicturesNotification->move(0, this->height());
	ui->noPicturesToCrop->move(0,this->height());
	ui->beginnerInstructions->move(0, this->height());
	ui->cropInstructions1->move(0, height());
	ui->cropInstructions2->move(0, height());
	ui->noPicturesToCrop->move(0, height());
	ui->connectedNotification->move(0, height());
	ui->connectionLostNotification->move(0, height());
	ui->waveDiagram->move(0, height());
	ui->waveInstruction->move(0, height());

	//make all the states.
    m_emptyState = new QState(m_machine);
    hideAllExtraWidgets(m_emptyState);
	m_emptyState->assignProperty(ui->beginnerInstructions, "geometry", QRect(0, height(), ui->beginnerInstructions->width(), ui->beginnerInstructions->height()));
	m_machine->setInitialState(m_emptyState);

    m_loadState = new QState(m_machine);
    hideAllExtraWidgets(m_loadState);
    m_loadState->assignProperty(ui->closeButton,"geometry", QRect(190, 100, 70, 70));
    m_loadState->assignProperty(ui->importBackground, "geometry", QRect(width()/2-ui->importBackground->width()/2, height()/2-ui->importBackground->height()/2+20, ui->importBackground->width(), ui->importBackground->height()));
    m_loadState->assignProperty(ui->loadInstructions, "geometry", QRect(width()/2-ui->loadInstructions->width()/2, height()/2-ui->importBackground->height()/2-ui->loadInstructions->height()+40, ui->loadInstructions->width(), ui->loadInstructions->height()));
    m_loadState->assignProperty(ui->leftArrow, "geometry", QRect(width()/2-ui->importBackground->width()/2-(ui->leftArrow->width()-200), height()/2, ui->leftArrow->width(), ui->leftArrow->height()));
	m_loadState->assignProperty(ui->rightArrow, "geometry", QRect(width()/2+ui->importBackground->width()/2-200, height()/2, ui->rightArrow->width(), ui->rightArrow->height()));

    m_chooseCropPhotoState = new QState(m_machine);
    hideAllExtraWidgets(m_chooseCropPhotoState);
    m_chooseCropPhotoState->assignProperty(ui->cropInstructions1, "geometry", QRect((this->width() / 2) - (ui->cropInstructions1->width() / 2), height()/10, ui->cropInstructions1->width(), ui->cropInstructions1->height()));
    
	m_cropState = new QState(m_machine);
    hideAllExtraWidgets(m_cropState);
    m_cropState->assignProperty(ui->croppingWidget, "geometry", QRect((this->width() / 2) - (ui->croppingWidget->width() / 2), (this->height() / 2) - (ui->croppingWidget->height() / 2), ui->croppingWidget->width(), ui->croppingWidget->height()));
    m_cropState->assignProperty(ui->undoButton, "geometry", QRect(70,140,ui->undoButton->width(),ui->undoButton->height()));
	m_cropState->assignProperty(ui->cropInstructions2, "geometry", QRect((this->width() / 2) - (ui->cropInstructions2->width() / 2), height()/10, ui->cropInstructions2->width(), ui->cropInstructions2->height()));
	m_cropState->assignProperty(ui->importBackground, "geometry", QRect(width()/2-ui->importBackground->width()/2, height()/2-ui->importBackground->height()/2+20, ui->importBackground->width(), ui->importBackground->height()));

    m_menuState = new QState(m_machine);
    hideAllExtraWidgets(m_menuState);
	int geomWidth = geom.width();
	int geomHeight = geom.height();
	int backButtonWidth = ui->backButton->width();
	int backButtonHeight = ui->backButton->height();
	m_menuState->assignProperty(ui->importButton, "geometry", QRect(geomWidth/4-backButtonWidth/2, geomHeight/3-backButtonHeight/2-80, 250, 250));
    m_menuState->assignProperty(ui->backButton, "geometry", QRect(2*geomWidth/4-backButtonWidth/2, geomHeight/3-backButtonHeight/2-80, 250, 250));
    m_menuState->assignProperty(ui->loadButton, "geometry", QRect(3*geomWidth/4-backButtonWidth/2, geomHeight/3-backButtonHeight/2-80, 250, 250));
    m_menuState->assignProperty(ui->exportButton, "geometry", QRect(geomWidth/4-backButtonWidth/2, 2*geomHeight/3-backButtonHeight/2, 250, 250));
    m_menuState->assignProperty(ui->saveButton, "geometry", QRect(3*geomWidth/4-backButtonWidth/2, 2*geomHeight/3-backButtonHeight/2, 250, 250));
    m_menuState->assignProperty(ui->cropButton, "geometry", QRect(2*geomWidth/4-backButtonWidth/2, 2*geomHeight/3-backButtonHeight/2, 250, 250));

    m_helpState = new QState(m_machine);
    hideAllExtraWidgets(m_helpState);
    m_helpState->assignProperty(ui->closeButton, "geometry",QRect(90,140, 70, 70));
	m_helpState->assignProperty(ui->helpWidget, "geometry", QRect((this->width()/2) - (ui->helpWidget->width()/2) - 50, (this->height()/2) - (ui->helpWidget->height()/2) + 80, width(), height()));

    m_colorState = new ColorState(m_machine, m_desk);
    hideAllExtraWidgets(m_colorState);
    m_colorState->assignProperty(ui->undoButton,"geometry", QRect(70, 140, ui->undoButton->width(), ui->undoButton->height()));
	m_colorState->assignProperty(ui->colorInstructions, "geometry", QRect(width()/2-ui->colorInstructions->width()/2, height()/40, ui->colorInstructions->width(), ui->colorInstructions->height()));
	connect(this, SIGNAL(colorChanged()), m_desk, SLOT(slotUpdateLastColor()));
	
	m_importState = new QState(m_machine);
    hideAllExtraWidgets(m_importState);
    m_importState->assignProperty(ui->closeButton,"geometry", QRect(190, 100, 70, 70));
    m_importState->assignProperty(ui->importBackground, "geometry", QRect(width()/2-ui->importBackground->width()/2, height()/2-ui->importBackground->height()/2+20, ui->importBackground->width(), ui->importBackground->height()));
    m_importState->assignProperty(ui->importInstruction, "geometry", QRect(width()/2-ui->importInstruction->width()/2, height()/20, ui->importInstruction->width(), ui->importInstruction->height()));
	m_importState->assignProperty(ui->leftArrow, "geometry", QRect(width()/2-ui->importBackground->width()/2-(ui->leftArrow->width()-200), height()/2, ui->leftArrow->width(), ui->leftArrow->height()));
	m_importState->assignProperty(ui->rightArrow, "geometry", QRect(width()/2+ui->importBackground->width()/2-200, height()/2, ui->rightArrow->width(), ui->rightArrow->height()));

	//For importState:
    m_importFiles = QStringList();
    updateImportFiles();
    m_importIndex = 0;
	initForImporting();

	 QDir dir = QDir("C:/Users/Public/Pictures/FotoKinect/");
	 if (!dir.exists()) {
		 dir.mkdir("C:/Users/Public/Pictures/FotoKinect/");
	 }
	 dir = QDir("C:/Users/Public/Pictures/FotoKinect/Pictures To Import");
	 if (!dir.exists()) {
		 dir.mkdir("C:/Users/Public/Pictures/FotoKinect/Pictures To Import");
	 }

	//for loadState:
	m_loadFiles = QStringList();
	updateLoadFiles();
	m_loadIndex = 0;
	initForLoading();

	//make all the transitions 
	// transitions from empty state
    m_emptyState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
	m_emptyState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);

	// transitions from help state
    m_helpState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
	m_helpState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);
    m_helpState->addTransition(ui->helpButton, SIGNAL(clicked()), m_emptyState);

	// transitions from menu state
	m_menuState->addTransition(ui->menuButton, SIGNAL(clicked()), m_emptyState);
	m_menuState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
	m_menuState->addTransition(ui->backButton, SIGNAL(clicked()), m_colorState);
	m_menuState->addTransition(ui->cropButton, SIGNAL(clicked()), m_chooseCropPhotoState);
	m_menuState->addTransition(ui->importButton, SIGNAL(clicked()), m_importState);
	m_menuState->addTransition(this, SIGNAL(projectSaved()), m_emptyState);
	m_menuState->addTransition(this, SIGNAL(projectExported()), m_emptyState);
	m_menuState->addTransition(ui->loadButton, SIGNAL(clicked()), m_loadState);

	// transitions from load state
	m_loadState->addTransition(this, SIGNAL(projectLoaded()), m_emptyState);
	m_loadState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
	m_loadState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
    m_loadState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);

	// transitions from import state
	m_importState->addTransition(ui->importMenuButton, SIGNAL(clicked()), m_emptyState);
	m_importState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
	m_importState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
    m_importState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);
	m_importState->addTransition(this, SIGNAL(pictureImported()), m_emptyState);

	// transitions from color state
    m_colorState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);
	m_colorState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
    m_colorState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
	m_colorState->addTransition(this, SIGNAL(colorChanged()), m_emptyState);
	m_colorState->addTransition(ui->undoButton, SIGNAL(clicked()), m_emptyState);

	// transitions from choose crop photo state
	m_chooseCropPhotoState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);
	m_chooseCropPhotoState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
	m_chooseCropPhotoState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
	m_chooseCropPhotoState->addTransition(this, SIGNAL(cropPhotoSelected()), m_cropState);

	// transitions from crop state
	m_cropState->addTransition(ui->closeButton, SIGNAL(clicked()), m_emptyState);
	m_cropState->addTransition(ui->menuButton, SIGNAL(clicked()), m_menuState);
	m_cropState->addTransition(ui->helpButton, SIGNAL(clicked()), m_helpState);
	m_cropState->addTransition(this, SIGNAL(pictureCropped()), m_emptyState);
	m_cropState->addTransition(ui->undoButton, SIGNAL(clicked()), m_emptyState);

	// connect clicked signal to slot deselect to deselect all pictures
	connect(ui->helpButton, SIGNAL(clicked()), this, SLOT(slotDeselectAll()));
	connect(ui->menuButton, SIGNAL(clicked()), this, SLOT(slotDeselectAll()));

    m_machine->start();

    // set the startup project mode
    m_modeInfo.setDeskDpi(ui->canvas->logicalDpiX(), ui->canvas->logicalDpiY());

    ui->cursor_1->setVisible(false);
    ui->cursor_2->setVisible(false);

	//Start Device Manager
    m_deviceManager = new DeviceManager(*this, *m_desk);
}


void MainWindow::initForImporting(){
    int MAX_IMPORT_WIDTH = 600;
    int MIN_IMPORT_X = (this->width() / 2) - (MAX_IMPORT_WIDTH / 2);
    int MAX_IMPORT_X = MIN_IMPORT_X + MAX_IMPORT_WIDTH ;
        
    if (m_importFiles.count()==0){
		m_importState->assignProperty(ui->noPicturesNotification, "geometry", QRect((width() / 2) - (ui->noPicturesNotification->width() / 2), (height() / 2) - (ui->noPicturesNotification->height() / 2)-50, ui->noPicturesNotification->width(), ui->noPicturesNotification->height()));
    }

    QPixmap pixmap;
    if (m_importFiles.count()>0){
		//big center thumbnail
		pixmap = QPixmap(m_importFiles[m_importIndex]);
		pixmap = pixmap.scaled(ui->importMenu->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        m_importState->assignProperty(ui->importMenu, "geometry", QRect((this->width() / 2) - (pixmap.width() / 2), (this->height() / 2) - (ui->importMenu->height() / 2)-50, ui->importMenu->width(), ui->importMenu->height()));
        ui->importMenu->setPixmap(pixmap);

		// center (current) thumbnail
        pixmap = QPixmap(m_importFiles[m_importIndex]);
		pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        m_importState->assignProperty(ui->importMenuThumb2, "geometry", QRect((this->width() / 2) - (pixmap.width() / 2), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250, ui->importMenuThumb2->width(), ui->importMenuThumb2->height()));
        ui->importMenuThumb2->setPixmap(pixmap);
    }

    if (m_importFiles.count()>=2){
		// left (previous) thumbnail
		pixmap = QPixmap(this->getPreviousImportFile());
		pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
		m_importState->assignProperty(ui->importMenuThumb1, "geometry", QRect(MIN_IMPORT_X + (pixmap.width() / 4), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250, ui->importMenuThumb1->width(), ui->importMenuThumb1->height()));
		ui->importMenuThumb1->setPixmap(pixmap);

		// right (next) thumbnail
		pixmap = QPixmap(this->getNextImportFile());
		pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
		m_importState->assignProperty(ui->importMenuThumb3, "geometry", QRect(MAX_IMPORT_X - (pixmap.width() * 1.25), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250, ui->importMenuThumb3->width(), ui->importMenuThumb3->height()));
		ui->importMenuThumb3->setPixmap(pixmap);
	}
}

void MainWindow::initForLoading(){
	int MAX_LOAD_WIDTH = 600;
    int MIN_LOAD_X = (this->width() / 2) - (MAX_LOAD_WIDTH / 2);
    int MAX_LOAD_X = MIN_LOAD_X + MAX_LOAD_WIDTH ;

	if (m_loadFiles.count()==0){
		m_loadState->assignProperty(ui->noProjectNotification, "geometry", QRect((width() / 2) - (ui->noProjectNotification->width() / 2), (height() / 2) - (ui->noProjectNotification->height() / 2)-50, ui->noProjectNotification->width(), ui->noProjectNotification->height()));
	}
	else if (m_loadFiles.count()>0){
		m_loadState->assignProperty(ui->loadMenu, "geometry", QRect((this->width() / 2) - (ui->loadMenu->width() / 2), (this->height() / 2) - (ui->loadMenu->height() / 2)-50, ui->loadMenu->width(), ui->loadMenu->height()));
		m_loadState->assignProperty(ui->loadMenuThumb2, "geometry", QRect((this->width() / 2) - (ui->loadMenuThumb2->width() / 2), (this->height() / 2) - (ui->loadMenuThumb2->height() / 2) + 250, ui->loadMenuThumb2->width(), ui->loadMenuThumb2->height()));
	
		ui->loadMenu->setText(parseProjectDate(m_loadFiles[m_loadIndex]));
		ui->loadMenuTime->setText(parseProjectTime(m_loadFiles[m_loadIndex]));
	
		ui->loadMenuThumb2->setText(parseProjectDate(m_loadFiles[m_loadIndex]));
		ui->loadMenuThumb2Time->setText(parseProjectTime(m_loadFiles[m_loadIndex]));
        ui->loadMenuThumb2->move((this->width() / 2) - (ui->loadMenuThumb2->width() / 2), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250);
	}
	
	if (m_loadFiles.count()>=2){
		// left (previous) thumbnail
		ui->loadMenuThumb1->setText(this->getPreviousLoadFile().remove(".fotowall"));
		m_loadState->assignProperty(ui->loadMenuThumb1, "geometry", QRect(MIN_LOAD_X + (ui->loadMenuThumb1->width() / 4), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250, ui->loadMenuThumb1->width(), ui->loadMenuThumb1->height()));
   
		// right (next) thumbnail
		ui->loadMenuThumb3->setText(this->getNextLoadFile().remove(".fotowall"));
		m_loadState->assignProperty(ui->loadMenuThumb3, "geometry", QRect(MAX_LOAD_X - (ui->loadMenuThumb3->width() * 1.25), (this->height() / 2) - (ui->loadMenuThumb3->height() / 2) + 250, ui->loadMenuThumb3->width(), ui->loadMenuThumb3->height()));
	}
}


void MainWindow::updateImportFiles(){
	// build the extensions list
    QStringList extensions;
    foreach (const QByteArray & format, QImageReader::supportedImageFormats()) {
        extensions.append("." + format);
        extensions.append("." + format.toUpper());
    }
	
    // get files in directory
    QDir dir = QDir("C:/Users/Public/Pictures/FotoKinect/Pictures To Import");
    QStringList allFiles = dir.entryList();

    // filter filenames by extensions
	m_importFiles.clear();
    QStringList filteredFiles;
    foreach (QString extension, extensions) {
        filteredFiles = allFiles.filter(extension);
        m_importFiles += filteredFiles;
    }

	//add path in front of fileName
	int i;
 	for (i = 0; i < m_importFiles.size(); i++) {
  	    m_importFiles[i] = dir.path() + dir.separator() + m_importFiles[i];
  	}
}

void MainWindow::updateLoadFiles(){
	// get files in directory
    QDir dir2 = QDir("C:/Users/Public/Pictures/FotoKinect/Projects");
    QStringList allFiles2 = dir2.entryList();
	
	if (allFiles2.isEmpty()==false){
		//get a fresh QStringList of import files
		m_loadFiles = allFiles2.filter(".fotowall");
	}
}
void MainWindow::hideAllExtraWidgets(QState * state){
    state->assignProperty(ui->backButton, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->importButton, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->exportButton, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->loadButton, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->saveButton, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->cropButton, "geometry", QRect(0, height(), 250, 250));    
	state->assignProperty(ui->importMenu, "geometry", QRect(0, height(), 250, 250));
	state->assignProperty(ui->importMenuThumb1, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->importMenuThumb2, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->importMenuThumb3, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->importBackground, "geometry", QRect(0, height(), 250, 250));
    state->assignProperty(ui->helpWidget, "geometry", QRect(width(), -height(), 250, 250));
    state->assignProperty(ui->closeButton, "geometry", QRect(width(), -height(), 250, 250));
	state->assignProperty(ui->importInstruction, "geometry", QRect(0, height(), ui->importInstruction->width(), ui->importInstruction->height()));
	state->assignProperty(ui->pushDiagram, "geometry",  QRect(0, height(), ui->pushDiagram->width(), ui->pushDiagram->height()));
	state->assignProperty(ui->loadMenu, "geometry", QRect(0, height(), ui->loadMenu->width(), ui->loadMenu->height()));
    state->assignProperty(ui->loadMenuTime, "geometry", QRect(0, height(), ui->loadMenuTime->width(), ui->loadMenuTime->height()));
	state->assignProperty(ui->loadMenuThumb1, "geometry", QRect(0, height(),ui->loadMenuThumb1->width(), ui->loadMenuThumb1->height()));
    state->assignProperty(ui->loadMenuThumb1Time, "geometry", QRect(0, height(), ui->loadMenuThumb1Time->width(), ui->loadMenuThumb1Time->height()));
	state->assignProperty(ui->loadMenuThumb2, "geometry", QRect(0, height(), ui->loadMenuThumb1->width(), ui->loadMenuThumb2->height()));
	state->assignProperty(ui->loadMenuThumb2Time, "geometry", QRect(0, height(),ui->loadMenuThumb1->width(), ui->loadMenuThumb2->height()));
	state->assignProperty(ui->loadMenuThumb3, "geometry", QRect(0, height(),ui->loadMenuThumb1->width(), ui->loadMenuThumb3->height()));
	state->assignProperty(ui->loadMenuThumb3Time, "geometry", QRect(0, height(), ui->loadMenuThumb1->width(), ui->loadMenuThumb3Time->height()));
	state->assignProperty(ui->noPicturesNotification, "geometry", QRect(0, height(), ui->noPicturesNotification->width(), ui->noPicturesNotification->height()));
	state->assignProperty(ui->noProjectNotification, "geometry", QRect(0, height(), ui->noProjectNotification->width(), ui->noProjectNotification->height()));
	state->assignProperty(ui->importMenuButton, "geometry", QRect(0, height(), ui->importMenuButton->width(), ui->importMenuButton->height()));
	state->assignProperty(ui->croppingWidget, "geometry", QRect(0, height(), ui->croppingWidget->width(), ui->croppingWidget->height()));
	state->assignProperty(ui->cropInstructions1, "geometry", QRect(0, height(), ui->cropInstructions1->width(), ui->cropInstructions1->height()));
	state->assignProperty(ui->cropInstructions2, "geometry", QRect(0, height(), ui->cropInstructions2->width(), ui->cropInstructions2->height()));
	state->assignProperty(ui->colorInstructions, "geometry", QRect(0, height(), ui->colorInstructions->width(), ui->colorInstructions->height()));
	state->assignProperty(ui->loadInstructions, "geometry", QRect(0, height(), ui->loadInstructions->width(), ui->loadInstructions->height()));
	state->assignProperty(ui->beginnerInstructions, "geometry", QRect(0, height(), ui->beginnerInstructions->width(), ui->beginnerInstructions->height()));
    state->assignProperty(ui->leftArrow, "geometry", QRect(0, height(), ui->leftArrow->width(), ui->leftArrow->height()));
    state->assignProperty(ui->rightArrow, "geometry", QRect(0, height(), ui->rightArrow->width(), ui->rightArrow->height()));
	state->assignProperty(ui->undoButton, "geometry", QRect(0, height(), ui->undoButton->width(), ui->undoButton->height()));
}

MainWindow::~MainWindow()
{
    // dump current layout
    saveXml(QDir::tempPath() + QDir::separator() + "autosave.fotowall");

	//delete timers
	delete m_hideLostInstr1Timer;
	delete m_hideLostInstr2Timer;
	delete m_hideLostInstrBeginTimer;
	delete m_cursorDetectedTimer;
	delete m_cursorDetected2Timer;
	delete m_savedTimer;
	delete m_exportedTimer;
	delete m_erasedTimer;
	delete m_cursor1GreenTimer;
	delete m_cursor2GreenTimer;
	delete m_connectedNotificationTimer;
	delete m_noPicturesToCropTimer;
	
	//delete states
	delete m_importState;
	delete m_menuState;
	delete m_emptyState;
	delete m_helpState;
	delete m_colorState;

	delete m_machine;

    // delete everything else
    delete m_desk;
	delete m_deviceManager;
    delete ui;
}

void MainWindow::loadXml(const QString & filePath)
{
    if (filePath.isNull())
        return;
    XmlRead *xmlRead = 0;
    try {
        xmlRead = new XmlRead(filePath);
    } catch (...) {
        // If loading failed
        return;
    }
    xmlRead->readDesk(m_desk);
    xmlRead->readContent(m_desk);
    delete xmlRead;
}

void MainWindow::saveXml(const QString & filePath) const
{
    XmlSave *xmlSave = 0;
    try {
        xmlSave = new XmlSave(filePath);
    } catch (...) {
        //if saving failled
        return;
    }

    xmlSave->saveDesk(m_desk);
    xmlSave->saveContent(m_desk);
    delete xmlSave;
}

void MainWindow::loadImages(QStringList &imagesPath)
{
    m_desk->addPictures(imagesPath);
}

void MainWindow::setNormalProject()
{
    m_modeInfo.setRealSizeInches(-1,-1); // Unset the size (for the saving function)
    static bool skipFirstMaximizeHack = true;
    ui->canvas->setMinimumSize(ui->canvas->minimumSizeHint());
    ui->canvas->setMaximumSize(QSize(16777215, 16777215));
    if (skipFirstMaximizeHack)
        skipFirstMaximizeHack = false;
    else
        showMaximized();
    ui->exportButton->setText(tr("Export"));
}


#ifdef Q_WS_WIN
/**
  Blur behind windows (on Windows Vista/7)

  The following code snippet has been borrowed from Jens of Qt Software / Nokia
  see: http://labs.qt.nokia.com/blogs/2009/09/15/using-blur-behind-on-windows/
  the license says: Use, modification and distribution is allowed without
  limitation, warranty, liability or support of any kind.
**/
#include <QLibrary>
#include <qt_windows.h>

// Dwm Data Structures
#define DWM_BB_ENABLE                 0x00000001  // fEnable has been specified
typedef struct _DWM_BLURBEHIND
{
    DWORD dwFlags;
    BOOL fEnable;
    HRGN hRgnBlur;
    BOOL fTransitionOnMaximized;
} DWM_BLURBEHIND;

// Dwm entry points
typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL * pfEnabled);
typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND hWnd, const DWM_BLURBEHIND * pBlurBehind);

#endif

void MainWindow::on_quitButton_clicked(){
	exit (0);
}

void MainWindow::on_saveButton_clicked()
{
	//make directory if it doesn't yet exist.
	QDir dir = QDir("C:/Users/Public/Pictures/FotoKinect/Projects");
	if (!dir.exists()) {
		dir.mkdir("C:/Users/Public/Pictures/FotoKinect/Projects");
	}

	QString dateString = QDateTime::currentDateTime().toString("ddMMyy_hhmmss");
	QString fileName = "C:/Users/Public/Pictures/FotoKinect/Projects/"+dateString+".fotowall";
	
    saveXml(fileName);

	//display message to user.
	ui->saveNotification->move(width()/2-ui->saveNotification->width()/2, height()/2-ui->saveNotification->height()/2);
	ui->projectsDirectory->move(width()/2-ui->projectsDirectory->width()/2, height()/2-ui->saveNotification->height()/2+ui->saveNotification->height());
	m_savedTimer->setInterval(2000);
	m_savedTimer->setSingleShot(true);
	m_savedTimer->start();

	emit projectSaved();
}

void MainWindow::on_exportButton_clicked()
{
	//make directory if it doesn't yet exist.
	QDir dir = QDir("C:/Users/Public/Pictures/FotoKinect/Exported Images/");
	if (!dir.exists()) {
		dir.mkdir("C:/Users/Public/Pictures/FotoKinect/Exported Images");
	}

	QString dateString = QDateTime::currentDateTime().toString("ddMMyy_hhmmss");
	QString fileName = "C:/Users/Public/Pictures/FotoKinect/Exported Images/"+dateString+".png";

    //  get the rendering size
    QSize imageSize(m_desk->width(), m_desk->height());

    // render the image
    QImage image;
	image = m_desk->renderedImage(imageSize, Qt::KeepAspectRatio);

    // save image
    if (image.save(fileName) && QFile::exists(fileName)) {
    } else {
        QMessageBox::warning(this, tr("Rendering Error"), tr("Error rendering to the file '%1'").arg(fileName));
	}

	ui->exportNotification->move(width()/2-ui->exportNotification->width()/2, height()/2-ui->exportNotification->height()/2);
	ui->exportDirectory->move(width()/2-ui->exportDirectory->width()/2, height()/2-ui->exportNotification->height()/2+ui->exportNotification->height());
	m_exportedTimer->setInterval(2000);
	m_exportedTimer->setSingleShot(true);
	m_exportedTimer->start();

	emit projectExported();
	return;
}

//adding cursors.
void MainWindow::slotAddInput(InputPoint p){
    if (p.id() == 1){
        ui->cursor_1->setVisible(true);
        m_showCursorOneFoundInstr=true;
    }
    if (p.id() == 2){
        ui->cursor_2->setVisible(true);
        m_showCursorTwoFoundInstr=true;
    }
    ui->waveInstruction->move(0, height());
	ui->waveDiagram->move(0,height());
}

//removing cursors.
void MainWindow::slotRemoveInput(int id, bool switchedCursors){
	if (id == 1){ //there's only one pointer, and it's being removed.
		ui->cursor_1->hide();
		if (m_firstCursor==false){ //At the beginning, a more detailed message is shown.
			ui->cursorLostInstruction->move(ui->cursor_1->pos());
			m_hideLostInstr1Timer->setInterval(2000);
			m_hideLostInstr1Timer->setSingleShot(true);
			m_hideLostInstr1Timer->start();
        }
        else{
            ui->cursorLostInstructionBegin->move(ui->cursor_1->pos());
            m_firstCursor=false;
			m_hideLostInstrBeginTimer->setInterval(2000);
			m_hideLostInstrBeginTimer->setSingleShot(true);
			m_hideLostInstrBeginTimer->start();
        }
		ui->cursor_1->move(-50,-50);
    }
    if (id == 2) { //there are two pointers and one of them is being removed.
		ui->cursor_2->hide();
        if (m_firstCursor==false){
			if (switchedCursors==false){ //the secondary cursor is being removed.
				ui->cursorLostInstruction2->move(ui->cursor_2->pos()); 
				m_hideLostInstr2Timer->setInterval(2000);
				m_hideLostInstr2Timer->setSingleShot(true);
				m_hideLostInstr2Timer->start();
			}
			else {
				ui->cursorLostInstruction2->move(ui->cursor_1->pos());
				m_hideLostInstr2Timer->setInterval(2000);
				m_hideLostInstr2Timer->setSingleShot(true);
				m_hideLostInstr2Timer->start();
			}
			ui->cursor_2->move(-50,-50);
		}
		else{
			if (switchedCursors==false){
				ui->cursorLostInstructionBegin->move(ui->cursor_2->pos()); 
				m_hideLostInstrBeginTimer->setInterval(2000);
				m_hideLostInstrBeginTimer->setSingleShot(true);
				m_hideLostInstrBeginTimer->start();
			}
			else {
				ui->cursorLostInstructionBegin->move(ui->cursor_1->pos());
				m_hideLostInstrBeginTimer->setInterval(2000);
				m_hideLostInstrBeginTimer->setSingleShot(true);
				m_hideLostInstrBeginTimer->start();
			}
			m_firstCursor=false;
		}
	}
}

//the next few slots hide user-notifications. They are called after a certain time has elapsed.

void MainWindow::slotHideCursorDetected(){
    ui->cursorDetected->move(0, height());
    ui->pushInstruction->move(0,height());
	ui->pushDiagram->move(0,height());
	QSet<QAbstractState *> config = m_machine->configuration();
	if (m_firstTimeInEmptyState && config.contains(m_emptyState)){
		ui->beginnerInstructions->move(width()/2-ui->beginnerInstructions->width()/2, height()/2-ui->beginnerInstructions->height()/2);
		m_firstTimeInEmptyState=false;
	}
}

void MainWindow::slotHideCursorDetected2(){
	ui->cursorDetected2->move(0, height());
    ui->pushInstruction->move(0,height());
	ui->pushDiagram->move(0,height());
}

void MainWindow::slotHideLostCursorInstr(){
    ui->cursorLostInstruction->move(0,height());
}

void MainWindow::slotHideLostCursorInstr2(){
    ui->cursorLostInstruction2->move(0,height());
}

void MainWindow::slotHideConnectedNotification(){
    ui->connectedNotification->move(0,height());
}

void MainWindow::slotHideLostCursorInstrBegin(){
    ui->cursorLostInstructionBegin->move(0,height());
}

void MainWindow::slotHideExportNotification(){
    ui->exportNotification->move(0,height());
	ui->exportDirectory->move(0, height());
}

void MainWindow::slotHideSaveNotification(){
    ui->saveNotification->move(0,height());
	ui->projectsDirectory->move(0, height());
}

void MainWindow::slotHideEraseNotification(){
    ui->eraseNotification->move(0,height());
}

void MainWindow::slotHideNoPicturesToCrop(){
    ui->noPicturesToCrop->move(0,height());
}

/*change back color of cursor1.*/
void MainWindow::slotRevertCursor1(){
    ui->cursor_1->setStyleSheet("QWidget {border-image: url(:/graphics/cursor.png)}");
}

/*change back color of cursor2.*/
void MainWindow::slotRevertCursor2(){
    ui->cursor_2->setStyleSheet("QWidget {border-image: url(:/graphics/cursor.png)}");
}

void MainWindow::slotUpdateCursor(InputPoint p)
{
	double x, y;
	x = p.x()*width();
	y = height() - p.y()*height();

    //Draw First, and draw appropriate instructions.
	if (p.id() == 1) {
        ui->cursor_1->move(x - 15, y - 15);
        if (m_showCursorOneFoundInstr == true){
			ui->cursorDetected->move(x ,y);
            if (m_firstCursor == true) {
				ui->pushInstruction->move(x -80, y + 70);
				ui->pushDiagram->move(x +75, y + 120);
				m_cursorDetectedTimer->setInterval(4500);
			}
			else {
				m_cursorDetectedTimer->setInterval(2000);
			}
			m_cursorDetectedTimer->setSingleShot(true);
			m_cursorDetectedTimer->start();
            m_showCursorOneFoundInstr = false;
		}
    }
    if (p.id() == 2) {
        ui->cursor_2->move(x - 15, y - 15);
        if (m_showCursorTwoFoundInstr == true){
			ui->cursorDetected2->move(x, y);
			m_cursorDetected2Timer->setInterval(2000);
			m_cursorDetected2Timer->setSingleShot(true);
			m_cursorDetected2Timer->start();
            m_showCursorTwoFoundInstr = false;
		}
	}

    QPoint inputPos = QPoint(x, y);
		
    QSet<QAbstractState *> config = m_machine->configuration();

    // check for cropping state
	if(config.contains(m_cropState)) {

		inputPos = ui->croppingWidget->mapFrom(this, inputPos);

		// update cursor points
		if (p.id() == 1) {
			m_cropP1 = inputPos;
		}
		else if (p.id() == 2) {
			m_cropP2 = inputPos;
		}

		// get side lengths of cropping box
		double dx = abs(m_cropP1.x() - m_cropP2.x());
		double dy = abs(m_cropP1.y() - m_cropP2.y());

		QRect cropSelection;
		if (m_cropP1.y() < m_cropP2.y()) {
			if (m_cropP1.x() < m_cropP2.x()) {
				cropSelection = QRect(m_cropP1.x(), m_cropP1.y(), dx, dy);
			}
			else {
				cropSelection = QRect(m_cropP2.x(), m_cropP1.y(), dx, dy);
			}
		}
		else {
			if (m_cropP1.x() < m_cropP2.x()) {
				cropSelection = QRect(m_cropP1.x(), m_cropP2.y(), dx, dy);
			}
			else {
				cropSelection = QRect(m_cropP2.x(), m_cropP2.y(), dx, dy);
			}
		}

		ui->croppingWidget->updateRubberBand(cropSelection);	
    }


	// check for color state
	if (config.contains(m_colorState)) {

		if (m_desk->withinColorSelector(ui->cursor_1->pos()) && m_desk->withinColorSelector(ui->cursor_2->pos())) {

			if (ui->cursor_1->x() < ui->cursor_2->x()) {
				m_desk->updateColorSelectorHue(ui->cursor_1->pos());
				m_desk->updateColorSelectorValue(ui->cursor_2->pos());
			}
			else {
				m_desk->updateColorSelectorHue(ui->cursor_2->pos());
				m_desk->updateColorSelectorValue(ui->cursor_1->pos());
			}
			
		}
		else {

			if (m_desk->withinColorSelector(ui->cursor_1->pos())) {
				m_desk->updateColorSelector(ui->cursor_1->pos());
			}
			else {
				m_desk->updateColorSelector(ui->cursor_2->pos());
			}
		}
	}

	if (config.contains(m_emptyState)){
		QList<QPoint> points;
		points.append(ui->cursor_1->pos());
		points.append(ui->cursor_2->pos());
		m_desk->slotCheckHover(points);
	}
}

/*for selecting things with the "push" gesture.*/
void MainWindow::slotSelect(InputPoint p)
{
	//set cursor to green and start the timer to set it back
	if(p.id() == 1) {
		this->setCursorGreen(1);
		m_cursor1GreenTimer->setInterval(300);
		m_cursor1GreenTimer->setSingleShot(true);
		m_cursor1GreenTimer->start();
	}
	else {
		this->setCursorGreen(2);
		m_cursor2GreenTimer->setInterval(300);
		m_cursor2GreenTimer->setSingleShot(true);
		m_cursor2GreenTimer->start();
	}
    QPoint inputPos = QPoint(p.x()*width(), height()-p.y()*height());
	QPoint coord = ui->menuButton->mapFrom(this, inputPos);
	QRect cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);

    // menu button
	coord = ui->menuButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
	if (ui->menuButton->contentsRect().intersects(cursorRect)) {
        ui->menuButton->click();
        m_menuOpen = false;
		return;
    }

    // help button
	coord = ui->helpButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (ui->helpButton->contentsRect().intersects(cursorRect)) {
        ui->helpButton->click();
        return;
    }
    // trash button
	coord = ui->trashButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (ui->trashButton->contentsRect().intersects(cursorRect)) {
        ui->trashButton->click();
        if(m_desk->deletePicture()){
			ui->eraseNotification->move(ui->trashButton->x()-150, ui->trashButton->y()-80);
			m_erasedTimer->setInterval(2000);
			m_erasedTimer->setSingleShot(true);
			m_erasedTimer->start();
		}else{
			if (p.id() == 1){
				this->setCursorRed(1);
			}else{
				this->setCursorRed(2);
			}
		}
        return;
    }

	// quit button
	coord = ui->quitButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (ui->quitButton->contentsRect().intersects(cursorRect)) {
		ui->quitButton->click();
		return;
	}

	//get current state for the next few actions.
	QSet<QAbstractState *> config = m_machine->configuration();

	if(config.contains(m_menuState)) {
	    // import button
		coord = ui->importButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->importButton->contentsRect().intersects(cursorRect)) {
			//use the slot browse method to fix the menu's positioning
			updateImportFiles();
			ui->importButton->click();
			this->slotBrowseImportMenu(0);
			m_menuOpen = false;
        }
        // canvas button
		coord = ui->backButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->backButton->contentsRect().intersects(cursorRect)) {
            ui->backButton->click();
			m_menuOpen = false;
        }
        // load button
		coord = ui->loadButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->loadButton->contentsRect().intersects(cursorRect)) {
            updateLoadFiles();
			initForLoading();
			ui->loadButton->click();
			slotBrowseLoadMenu(0);
        }
        // export button
		coord = ui->exportButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->exportButton->contentsRect().intersects(cursorRect)) {
            ui->exportButton->click();
        }
        // save button
		coord = ui->saveButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->saveButton->contentsRect().intersects(cursorRect)) {
            ui->saveButton->click();
        }
        // crop button
		coord = ui->cropButton->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
        if (ui->cropButton->contentsRect().intersects(cursorRect)) {
			if (m_desk->containsPictures()) {
				ui->cropInstructions1->move(width()/2-ui->noPicturesToCrop->width()/2, height()/10);
				ui->cropButton->click();
			}
			else {
				if(p.id() == 1) 
					this->setCursorRed(1);
				else
					this->setCursorRed(2);
				ui->noPicturesToCrop->move(width()/2-ui->noPicturesToCrop->width()/2, height()/2-ui->noPicturesToCrop->height()/2);
				m_noPicturesToCropTimer->setInterval(2000);
				m_noPicturesToCropTimer->setSingleShot(true);
				m_noPicturesToCropTimer->start();
			}
        }
		return;
	}

	// cancel button
	coord = ui->closeButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (ui->closeButton->contentsRect().intersects(cursorRect)) {
		ui->closeButton->click();
        return;
    }

	// undo button
	coord = ui->undoButton->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (ui->undoButton->contentsRect().intersects(cursorRect)) {

		// check for color state exit
		if(config.contains(m_colorState)) {
			m_desk->resetColorSelector();
		}

		ui->undoButton->click();

        return;
    }

    // import photo selection
	coord = ui->importMenu->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (config.contains(m_importState) && ui->importMenu->contentsRect().intersects(cursorRect)) {
    
		if(m_importFiles.count() >= 1){
			this->importSelectedPhoto();
			emit pictureImported();
		}else{
			if (p.id() == 1){
				this->setCursorRed(1);
			}else{

				this->setCursorRed(2);
			}
		}
        return;
    }

    // crop photo
    coord = ui->croppingWidget->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
    if (config.contains(m_cropState)) {
		if (ui->undoButton->contentsRect().intersects(cursorRect)) {
			emit pictureCropped();
			return;
		}
        if (m_desk->cropPicture(ui->croppingWidget->getCroppingRect())) {
			emit pictureCropped();
			return;
		}
    }

	// color selection
	if (config.contains(m_colorState)) {
		emit colorChanged();
		return;
	}

	// load button
	coord = ui->loadMenu->mapFrom(this, inputPos);
	cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);

	QPoint coord2 = ui->loadMenuTime->mapFrom(this, inputPos);
	QRect cursorRect2 = QRect(coord2.x()-15, coord2.y()-15, 30,30);

    if (config.contains(m_loadState) && (ui->loadMenu->contentsRect().intersects(cursorRect) || ui->loadMenuTime->contentsRect().intersects(cursorRect2) )) {

		if(m_loadFiles.count() >= 1){
			this->loadSelectedPhoto();
			emit projectLoaded();
		}else{
			if (p.id() == 1){
				this->setCursorRed(1);
			}else{
				this->setCursorRed(2);
			}
		}
		return;
	}

	/* help menu states */
	if (config.contains(m_helpState)) {
		//introButton
		coord = ui->helpWidget->getIntroButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getIntroButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getIntroButton()->click();
		}

		//"skip to topics" button
		coord = ui->helpWidget->getTopicsButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getTopicsButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getTopicsButton()->click();
		}

		//flip button
		coord = ui->helpWidget->getFlipButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getFlipButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getFlipButton()->click();
		}

		//rotateButton
		coord = ui->helpWidget->getRotateButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getRotateButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getRotateButton()->click();
		}
		
		//importButton
		coord = ui->helpWidget->getImportButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getImportButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getImportButton()->click();
		}

		//loadButton
		coord = ui->helpWidget->getLoadButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getLoadButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getLoadButton()->click();
		}

		//exportButton
		coord = ui->helpWidget->getExportButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getExportButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getExportButton()->click();
		}

		//saveButton
		coord = ui->helpWidget->getSaveButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getSaveButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getSaveButton()->click();
		}

		//cropButton
		coord = ui->helpWidget->getCropButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getCropButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getCropButton()->click();
		}

		//background button
		coord = ui->helpWidget->getBackgroundButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getBackgroundButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getBackgroundButton()->click();
		}

		//erasebutton
		coord = ui->helpWidget->getEraseButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getEraseButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getEraseButton()->click();
		}

		//skewbutton
		coord = ui->helpWidget->getSkewButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getSkewButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getSkewButton()->click();
		}

		//resizeButton
		coord = ui->helpWidget->getResizeButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getResizeButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getResizeButton()->click();
		}

		//reorderButton
		coord = ui->helpWidget->getReorderButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getReorderButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getReorderButton()->click();
		}

		//moveButton
		coord = ui->helpWidget->getMoveButton()->mapFrom(this, inputPos);
		cursorRect = QRect(coord.x()-15, coord.y()-15, 30,30);
		if (ui->helpWidget->getMoveButton()->contentsRect().intersects(cursorRect)) {
			this->ui->helpWidget->getMoveButton()->click();
		}
		return;
	}

	if (config.contains(m_emptyState) || config.contains(m_chooseCropPhotoState)){
		bool photoSelected = m_desk->slotSelect(p);
		// if in choose crop photo state, emit signal to enter crop states
		if (photoSelected && config.contains(m_chooseCropPhotoState)) {
			emit cropPhotoSelected();
			m_desk->beginCropMode(*(ui->croppingWidget));
			ui->croppingWidget->move((this->width()/2) - (ui->croppingWidget->width()/2), (this->height()/2) - (ui->croppingWidget->height()/2) + 20);
		}
	
		//if a photo was clicked, stop the timer that will revert it
		if(photoSelected && !config.contains(m_chooseCropPhotoState)) {
			if(p.id() == 1) {
				m_cursor1GreenTimer->stop();
			}
		}
		//if a photo was clicked, stop the timer that will revert it
		if(photoSelected && !config.contains(m_chooseCropPhotoState)) {
			if(p.id() == 1) {
				m_cursor1GreenTimer->stop();
			}
			else {
				m_cursor2GreenTimer->stop();
			}
		}
	}
}

void MainWindow::slotDeselect(InputPoint id) {
    m_desk->slotDeselect(id);
}

void MainWindow::slotDeselectAll() {
	this->slotDeselect(InputPoint(0,0,0,1));
	this->slotDeselect(InputPoint(0,0,0,2));
}

void MainWindow::slotBrowseImportMenu(int direction) {

    QSet<QAbstractState *> config = m_machine->configuration();
    // only register swipes if import menu is open
    if (config.contains(m_importState)) {
		if (m_importFiles.count()>1){
		if(direction != 0) {
			// get circular index         
			m_importIndex = (m_importIndex + direction) % m_importFiles.size();
			if (m_importIndex < 0) {
				m_importIndex += m_importFiles.size();
			}
		}

        int MAX_IMPORT_WIDTH = 600;
        int MIN_IMPORT_X = (this->width() / 2) - (MAX_IMPORT_WIDTH / 2);
        int MAX_IMPORT_X = MIN_IMPORT_X + MAX_IMPORT_WIDTH ;

        // scale and set pixmap, center widget
        QPixmap pixmap(m_importFiles[m_importIndex]);
        pixmap = pixmap.scaled(ui->importMenu->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        ui->importMenu->move((this->width() / 2) - (pixmap.width() / 2), (this->height() / 2) - (ui->importMenu->height() / 2)-50);
        ui->importMenu->setPixmap(pixmap);

        // left (previous) thumbnail
        pixmap = QPixmap(this->getNextImportFile());
        pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        ui->importMenuThumb1->move(MIN_IMPORT_X + (pixmap.width() / 4), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250);
        ui->importMenuThumb1->setPixmap(pixmap);

        // center (current) thumbnail
        pixmap = QPixmap(m_importFiles[m_importIndex]);
        pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        ui->importMenuThumb2->move((this->width() / 2) - (pixmap.width() / 2), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250);
        ui->importMenuThumb2->setPixmap(pixmap);

        // right (next) thumbnail
        pixmap = QPixmap(this->getPreviousImportFile());
        pixmap = pixmap.scaled(ui->importMenuThumb1->size(), Qt::KeepAspectRatio, Qt::FastTransformation);
        ui->importMenuThumb3->move(MAX_IMPORT_X - (pixmap.width() * 1.25), (this->height() / 2) - (ui->importMenuThumb1->height() / 2) + 250);
		ui->importMenuThumb3->setPixmap(pixmap);
		}
    }
}


void MainWindow::slotBrowseLoadMenu(int direction) {
	QSet<QAbstractState *> config = m_machine->configuration();
    if (config.contains(m_loadState)) {
		if (m_loadFiles.count()>1){
		if(direction != 0) {
			// get circular index
			m_loadIndex = (m_loadIndex + direction) % m_loadFiles.size();
			if (m_loadIndex < 0) {
				m_loadIndex += m_loadFiles.size();
			}
		}

        int MAX_LOAD_WIDTH = 800;
        int MIN_LOAD_X = (this->width() / 2) - (MAX_LOAD_WIDTH / 2.3);
        int MAX_LOAD_X = MIN_LOAD_X + MAX_LOAD_WIDTH ;

        // scale and set pixmap, center widget
		ui->loadMenu->setText(parseProjectDate(m_loadFiles[m_loadIndex]));
		ui->loadMenuTime->setText(parseProjectTime(m_loadFiles[m_loadIndex]));
                ui->loadMenu->move((this->width() / 2) - (ui->loadMenu->width() / 2), (this->height() / 2) - (ui->importMenu->height() / 2)-50);
		ui->loadMenuTime->move((this->width() / 2) - (ui->loadMenu->width() / 2), (this->height() / 2) - (ui->importMenu->height() / 2)-50+ui->loadMenu->height());

        // left (previous) thumbnail
		ui->loadMenuThumb1->setText(parseProjectDate(getNextLoadFile()));
		ui->loadMenuThumb1Time->setText(parseProjectTime(getNextLoadFile()));
                ui->loadMenuThumb1->move(MIN_LOAD_X, (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250);
		ui->loadMenuThumb1Time->move(MIN_LOAD_X, (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250+ui->loadMenuThumb1Time->height());

        // center (current) thumbnail
		ui->loadMenuThumb2->setText(parseProjectDate(m_loadFiles[m_loadIndex]));
		ui->loadMenuThumb2Time->setText(parseProjectTime(m_loadFiles[m_loadIndex]));
                ui->loadMenuThumb2->move((this->width() / 2) - (ui->loadMenuThumb2->width() / 2), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250);
		ui->loadMenuThumb2Time->move((this->width() / 2) - (ui->loadMenuThumb2->width() / 2), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250+ui->loadMenuThumb2->height());

        // right (next) thumbnail
		ui->loadMenuThumb3->setText(parseProjectDate(getPreviousLoadFile()));
		ui->loadMenuThumb3Time->setText(parseProjectTime(getPreviousLoadFile()));
        ui->loadMenuThumb3->move(MAX_LOAD_X - (ui->loadMenuThumb3->width() * 1.5), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250);
		ui->loadMenuThumb3Time->move(MAX_LOAD_X - (ui->loadMenuThumb3->width() * 1.5), (this->height() / 2) - (ui->loadMenuThumb1->height() / 2) + 250+ui->loadMenuThumb3->height());
		}
	}
}

//get date text to display to user from filename.
QString MainWindow::parseProjectDate(QString filename){
	QString newName;
	QString day = filename.left(2);
	int month = atoi(filename.mid(2,2).toStdString().c_str());
	QString monthString = QDate::shortMonthName(month);
	QString year = filename.mid(4,2);
	newName.append("<center>");
	newName.append(monthString);
	newName.append(" ");
	newName.append(day);
	newName.append(", ");
	newName.append(year);
	return newName;
}

//get time text to display to user from filename.
QString MainWindow::parseProjectTime(QString filename){
	QString newName;
	QString hour = filename.mid(7,2);
	QString minute = filename.mid(9,2);
	QString second = filename.mid(11,2);
	newName.append("<center>");
	newName.append(hour);
	newName.append(":");
	newName.append(minute);
	newName.append(":");
	newName.append(second);
	return newName;
}

//used to get photo thumbnails for import
QString MainWindow::getPreviousImportFile() {

    int i = (m_importIndex - 1) % m_importFiles.size();
    if (i < 0) {
        i += m_importFiles.size();
    }
    return m_importFiles[i];
}

QString MainWindow::getPreviousLoadFile() {
    int i = (m_loadIndex - 1) % m_loadFiles.size();
    if (i < 0) {
        i += m_loadFiles.size();
    }
    return m_loadFiles[i];
}

//used to get photo thumbnails for import
QString MainWindow::getNextImportFile() {
    return m_importFiles[(m_importIndex + 1) % m_importFiles.size()];
}

QString MainWindow::getNextLoadFile() {

    return m_loadFiles[(m_loadIndex + 1) % m_loadFiles.size()];
}

void MainWindow::importSelectedPhoto() {
    QStringList file;
    file.append(m_importFiles[m_importIndex]);

    QSettings s;
    m_desk->addPictures(file);
    QFileInfo path(file[0]);
    s.setValue("fotowall/loadImagesDir", path.absolutePath());
}

void MainWindow::loadSelectedPhoto() {
	QSettings s;
    QString fileName;
    fileName=m_loadFiles[m_loadIndex];
    if (fileName.isNull())
        return;

	fileName.prepend("C:/Users/Public/Pictures/FotoKinect/Projects/");
    QFileInfo path(fileName);
    s.setValue("fotowall/loadProjectDir", path.absolutePath());
    loadXml(fileName);
}

void MainWindow::setCursorGreen(int cursorID) {
	if(cursorID == 1) {
		ui->cursor_1->setStyleSheet("QWidget {border-image: url(:/graphics/cursorgreen.png)}");
	}
	else {
		ui->cursor_2->setStyleSheet("QWidget {border-image: url(:/graphics/cursorgreen.png)}");
	}
}

void MainWindow::setCursorRed(int cursorID) {
	if(cursorID == 1) {
		ui->cursor_1->setStyleSheet("QWidget {border-image: url(:/graphics/cursorred.png)}");
	}
	else {
		ui->cursor_2->setStyleSheet("QWidget {border-image: url(:/graphics/cursorred.png)}");
	}
}

//called when the Kinect is connected.
void MainWindow::slotDeviceConnected() {
	ui->waitingForDeviceInput->move(0,height());
    ui->title->move(0,this->height());
	ui->connectionLostNotification->move(0, height());

	ui->waveInstruction->move(width()/2-(ui->waveInstruction->width()/2), height()/2-(ui->waveInstruction->height()/2));
    ui->waveDiagram->move(width()/2-(ui->waveDiagram->width()/2), height()/2-(ui->waveInstruction->height()/2)+70);
	ui->connectedNotification->move(width()/2-(ui->waveInstruction->width()/2), height()/2-(ui->waveInstruction->height()/2)-100);
	m_connectedNotificationTimer->setInterval(2000);
	m_connectedNotificationTimer->setSingleShot(true);
	m_connectedNotificationTimer->start();
}

void MainWindow::slotDeviceDisconnected() {
	ui->connectionLostNotification->move(width()/2-(ui->waveInstruction->width()/2)+100, height()/2-(ui->waveInstruction->height()/2));
}

void MainWindow::makeNewDeviceManager() {
	delete m_deviceManager;
	m_deviceManager = new DeviceManager(*this, *m_desk);
}
